/*
 * Copyright [2021-present] [ahoo wang <ahoowang@qq.com> (https://github.com/Ahoo-Wang)].
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *      http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package me.ahoo.cosid.snowflake;

import me.ahoo.cosid.IdGenerator;
import me.ahoo.cosid.stat.generator.IdGeneratorStat;
import me.ahoo.cosid.stat.generator.SnowflakeIdStat;

/**
 * Snowflake algorithm ID generator.
 * 
 * <p>This interface implements the Twitter Snowflake ID generation algorithm,
 * which creates sortable, unique IDs across a distributed system. The algorithm
 * combines several components to form a 63-bit (positive long) ID:
 * 
 * <pre>
 * | timestamp | machine ID | sequence |
 * |-----------|------------|----------|
 * | 41 bits   | 10 bits    | 12 bits  |
 * </pre>
 * 
 * <p>The components are:
 * <ul>
 *   <li><strong>Timestamp</strong>: Milliseconds since a custom epoch</li>
 *   <li><strong>Machine ID</strong>: Unique identifier for the machine/instance</li>
 *   <li><strong>Sequence</strong>: Counter for IDs generated in the same millisecond</li>
 * </ul>
 * 
 * <p>This design ensures IDs are:
 * <ul>
 *   <li>Universally unique within the system</li>
 *   <li>Roughly time-ordered (sortable)</li>
 *   <li>Efficient to generate (no coordination required)</li>
 * </ul>
 * 
 * <p><img src="../doc-files/SnowflakeId.png" alt="SnowflakeId"></p>
 *
 * @author ahoo wang
 */
public interface SnowflakeId extends IdGenerator {
    /**
     * The total number of bits used for Snowflake IDs (63 bits).
     * 
     * <p>Snowflake IDs use 63 bits rather than 64 because the most significant
     * bit is reserved to ensure all IDs are positive long values.
     */
    int TOTAL_BIT = 63;

    /**
     * Get the epoch timestamp used as the base for time calculations.
     * 
     * <p>This is the timestamp (in milliseconds) that serves as the starting
     * point for the timestamp portion of generated IDs. IDs generated by this
     * instance will have timestamps relative to this epoch.
     *
     * @return The epoch timestamp in milliseconds
     */
    long getEpoch();

    /**
     * Get the number of bits used for the timestamp portion.
     * 
     * <p>This determines the range of time that can be represented by the
     * timestamp portion of the ID. More bits allow for a longer time range
     * but leave fewer bits for machine ID and sequence.
     *
     * @return The number of timestamp bits
     */
    int getTimestampBit();

    /**
     * Get the number of bits used for the machine ID portion.
     * 
     * <p>This determines how many unique machines can participate in ID
     * generation. More bits allow for more machines but leave fewer bits
     * for timestamp and sequence.
     *
     * @return The number of machine ID bits
     */
    int getMachineBit();

    /**
     * Get the number of bits used for the sequence portion.
     * 
     * <p>This determines how many IDs can be generated per time unit (e.g.,
     * per millisecond). More bits allow for higher throughput within a
     * single time unit but leave fewer bits for timestamp and machine ID.
     *
     * @return The number of sequence bits
     */
    int getSequenceBit();

    /**
     * Check if this Snowflake ID generator is safe for use in JavaScript.
     * 
     * <p>JavaScript can only safely represent integers up to 2^53 - 1. This
     * method checks if the total bit size of the ID (timestamp + machine +
     * sequence) is less than or equal to the maximum safe JavaScript number
     * of bits, as defined in {@link SafeJavaScriptSnowflakeId#JAVA_SCRIPT_MAX_SAFE_NUMBER_BIT}.
     *
     * @return {@code true} if the ID is JavaScript-safe, {@code false} otherwise
     */
    default boolean isSafeJavascript() {
        return (getTimestampBit() + getMachineBit() + getSequenceBit()) <= SafeJavaScriptSnowflakeId.JAVA_SCRIPT_MAX_SAFE_NUMBER_BIT;
    }

    /**
     * Get the maximum timestamp value that can be represented.
     * 
     * <p>This is the maximum value that can be stored in the timestamp portion
     * of the ID, which determines how long the generator can be used before
     * exhausting the timestamp space.
     *
     * @return The maximum timestamp value
     */
    long getMaxTimestamp();

    /**
     * Get the maximum machine ID value that can be represented.
     * 
     * <p>This is the maximum value that can be stored in the machine ID portion
     * of the ID, which determines how many unique machines can participate in
     * ID generation.
     *
     * @return The maximum machine ID value
     */
    int getMaxMachineId();

    /**
     * Get the maximum sequence value that can be represented.
     * 
     * <p>This is the maximum value that can be stored in the sequence portion
     * of the ID, which determines how many IDs can be generated per time unit.
     *
     * @return The maximum sequence value
     */
    long getMaxSequence();

    /**
     * Get the timestamp of the last ID that was generated.
     * 
     * <p>This is used for clock synchronization and to ensure proper ordering
     * of generated IDs. It can also help detect clock drift.
     *
     * @return The timestamp of the last generated ID
     */
    long getLastTimestamp();

    /**
     * Get the machine ID assigned to this generator.
     * 
     * <p>This is the unique identifier for the machine or instance that is
     * generating IDs, which ensures global uniqueness across the distributed
     * system.
     *
     * @return The machine ID
     */
    int getMachineId();

    /**
     * Calculate the default sequence reset threshold.
     * 
     * <p>This utility method calculates a threshold value that can be used
     * to determine when to reset the sequence counter, typically to half
     * of the maximum sequence value.
     *
     * @param sequenceBit The number of bits used for the sequence portion
     * @return The default sequence reset threshold
     */
    static long defaultSequenceResetThreshold(int sequenceBit) {
        return ~(-1L << (sequenceBit - 1));
    }

    /**
     * Get statistical information about this Snowflake ID generator.
     * 
     * <p>This method provides detailed information about the generator's
     * configuration and current state, including all the key parameters
     * that define its behavior.
     *
     * @return Statistical information about this Snowflake ID generator
     */
    @Override
    default IdGeneratorStat stat() {
        return new SnowflakeIdStat(
                getClass().getSimpleName(),
                getEpoch(),
                getTimestampBit(),
                getMachineBit(),
                getSequenceBit(),
                isSafeJavascript(),
                getMachineId(),
                getLastTimestamp(),
                idConverter().stat()
        );
    }
}
